﻿using System;
using System.Windows.Forms;
using DevelopersTestPad.Worksheets;

namespace DevelopersTestPad.AppFrame
{
    public partial class AppWindow : Form
    {
        public AppWindow()
        {
            InitializeComponent();

            // Initialize app context.
            AppContext.Current.MainWindow = this;

            // Use the custom toolstrip renderer to get the VS2012 color scheme.
            ToolStripManager.Renderer = new CustomToolStripRenderer();

            // Register event handlers.
            AppContext.Current.NewEditorPageRequest += NewEditorPageRequest;
            AppContext.Current.OpenFileRequest += OpenFileRequest;
            AppContext.Current.SaveFileRequest += SaveFileRequest;
            AppContext.Current.SaveFileAsRequest += SaveFileAsRequest;
            AppContext.Current.ExitApplicationRequest += ExitApplicationRequest;
            AppContext.Current.AppNotificationReceived += AppNotificationReceived;
            
            // Send application initialized notification.
            AppContext.Current.OnAppNotificationReceived(new AppNotificationEventArgs { Type  = AppNotificationType.Initialized } );

            // Open a new editor page.
            AppContext.Current.OnNewEditorPageRequest(new AppCommandEventArgs(AppCommandType.NewEditorPage));
        }

        /// <summary>
        /// Gets and sets the current WorksheetView.
        /// </summary>
        private WorksheetView CurrentWorksheetView
        {
            get
            {
                WorksheetView view = null;
                if (pnlWorksheetViewContainer.Controls.Count == 1)
                {
                    view = (WorksheetView)pnlWorksheetViewContainer.Controls[0];
                }
                return view;
            }
            set
            {
                pnlWorksheetViewContainer.Visible = false;

                // Passivate and remove the existing worksheet view.
                WorksheetView current = CurrentWorksheetView;
                if (current != null)
                {
                    current.Passivate();
                    pnlWorksheetViewContainer.Controls.Remove(current);
                    current.Dispose();
                }

                // Show the new worksheet view.
                pnlWorksheetViewContainer.Controls.Add(value);
                pnlWorksheetViewContainer.Visible = true;
                value.Activate();
            }
        }

        /// <summary>
        /// Gets the current worksheet.
        /// </summary>
        private Worksheet CurrentWorksheet
        {
            get 
            { 
                var view = CurrentWorksheetView;
                if (view != null)
                {
                    return view.Worksheet;
                }
                return null;
            }
        }

        /// <summary>
        /// Defines which app command are currently available and which are not.
        /// </summary>
        private AppCommandAvailabilities Availabilities { set; get; }
      
        /// <summary>
        /// Handles the Exit Application request.
        /// </summary>
        private void ExitApplicationRequest(object sender, AppCommandEventArgs e)
        {
            if (e.Handled == false)
            {
                Close();
                e.Handled = true;
            }
        }

        /// <summary>
        /// Handles the Open File request. 
        /// </summary>
        private void OpenFileRequest(object sender, AppCommandEventArgs e)
        {
            using (WorkerScope.CreateNew())
            {
                if (AllowChangeWorksheet() && e.Handled == false)
                {
                    if (openFileDialog.ShowDialog() == DialogResult.OK)
                    {
                        string fileName = openFileDialog.FileName;

                        Worksheet worksheet;
                        string message;
                        if (WorksheetManager.TryOpen(fileName, out worksheet, out message))
                        {
                            ShowWorksheet(worksheet);
                            e.Handled = true;
                        }
                        else
                        {
                            Messages.ShowError(message);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Handles the Save File request.
        /// </summary>
        private void SaveFileRequest(object sender, AppCommandEventArgs e)
        {
            using (WorkerScope.CreateNew())
            {
                if (e.Handled == false)
                {
                    Worksheet worksheet = CurrentWorksheet;

                    bool save = true;

                    string fileName = null;

                    if (worksheet.Existing)
                    {
                        fileName = worksheet.Location.FullName;
                    }
                    else
                    {
                        if (saveFileDialog.ShowDialog() == DialogResult.OK)
                        {
                            fileName = saveFileDialog.FileName;
                        }
                        else
                        {
                            save = false;
                        }
                    }

                    if (save)
                    {
                        string message;
                        if (WorksheetManager.TrySave(worksheet, fileName, out message))
                        {
                            e.Handled = true;
                        }
                        else
                        {
                            Messages.ShowError(message);                            
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Handles the Save File As request.
        /// </summary>
        private void SaveFileAsRequest(object sender, AppCommandEventArgs e)
        {
            using (WorkerScope.CreateNew())
            {
                if (e.Handled == false)
                {
                    if (saveFileDialog.ShowDialog() == DialogResult.OK)
                    {
                        string fileName = saveFileDialog.FileName;

                        string message;
                        if (WorksheetManager.TrySave(CurrentWorksheet, fileName, out message))
                        {
                            e.Handled = true;
                        }
                        else
                        {
                            Messages.ShowError(message);
                            
                        }
                    }
                }
            }
        }
        
        /// <summary>
        /// Handles the New Editor Page request.
        /// </summary>
        private void NewEditorPageRequest(object sender, AppCommandEventArgs e)
        {
            using (WorkerScope.CreateNew())
            {
                if (AllowChangeWorksheet() && e.Handled == false)
                {
                    Worksheet worksheet = WorksheetManager.CreateWorksheet(ActiveWorksheetType);
                    bool succeed = ShowWorksheet(worksheet); 
                    e.Handled = succeed;
                }
            }
        }

        /// <summary>
        /// Handles the app notification received event.
        /// </summary>
        private void AppNotificationReceived(object sender, AppNotificationEventArgs e)
        {
            Availabilities = AppCommandAvailabilities.Analyze(CurrentWorksheet);

            SetAppCommandAvailability(Availabilities.IsAvailable(AppCommandType.NewEditorPage), tsbNew, mniFileNew);
            SetAppCommandAvailability(Availabilities.IsAvailable(AppCommandType.OpenFile), mniFileOpen, tsbOpen);
            SetAppCommandAvailability(Availabilities.IsAvailable(AppCommandType.SaveFile), mniFileSave, tsbSave);
            SetAppCommandAvailability(Availabilities.IsAvailable(AppCommandType.SaveFileAs), mniFileSaveAs);
            SetAppCommandAvailability(Availabilities.IsAvailable(AppCommandType.ExitApplication));
            SetAppCommandAvailability(Availabilities.IsAvailable(AppCommandType.Execute), mniCommandExecute, tsbExecute);
            SetAppCommandAvailability(Availabilities.IsAvailable(AppCommandType.ShowOptions), mniToolsOptions);
            SetAppCommandAvailability(Availabilities.IsAvailable(AppCommandType.ShowAbout), mniHelpAbout);
        }
   
        /// <summary>
        /// Shows the worksheet.
        /// </summary>
        /// <param name="worksheet">The worksheet to show.</param>
        /// <returns>true</returns>
        private bool ShowWorksheet(Worksheet worksheet)
        {
            CurrentWorksheetView = WorksheetViewFactory.CreateWorksheetView(worksheet);
            
            AppContext.Current.OnAppNotificationReceived(new AppNotificationEventArgs { Type = AppNotificationType.WorksheetOpened});

            return true;
        }

        /// <summary>
        /// Checks if it is allowed to change the current worksheet.
        /// </summary>
        /// <returns>true/false</returns>
        private bool AllowChangeWorksheet()
        {
            bool allow = true;

            if (CurrentWorksheet != null && CurrentWorksheet.Status == WorksheetStatus.Dirty)
            {
                var result = Messages.ShowQuestion(string.Format("Want to save your changes to {0}?", CurrentWorksheet.Location.Name));
                if (result == DialogResult.Yes)
                {
                    AppCommandEventArgs e = new AppCommandEventArgs(AppCommandType.SaveFile);
                    AppContext.Current.OnSaveFileRequest(e);

                    if (e.Handled == false)
                    {
                        allow = false;
                    }
                }
                else if (result == DialogResult.Cancel)
                {
                    allow = false;
                }
            }

            return allow;
        }

        private static void SetAppCommandAvailability(bool isAvailable, params ToolStripItem[] controls)
        {
            foreach (ToolStripItem control in controls)
            {
                control.Enabled = isAvailable;
            }
        }

        private void AppWindow_FormClosing(object sender, FormClosingEventArgs e)
        {            
            AppContext.Current.Dispose();
        }

        #region Raise AppContext events

        /// <summary>
        /// Raises the corresponding AppContext event.
        /// </summary>
        private void mniFileNew_Click(object sender, EventArgs e)
        {
            AppContext.Current.OnNewEditorPageRequest(new AppCommandEventArgs(AppCommandType.NewEditorPage));
        }

        /// <summary>
        /// Raises the corresponding AppContext event.
        /// </summary>
        private void mniFileOpen_Click(object sender, EventArgs e)
        {
            AppContext.Current.OnOpenFileRequest(new AppCommandEventArgs(AppCommandType.OpenFile));
        }

        /// <summary>
        /// Raises the corresponding AppContext event.
        /// </summary>
        private void mniFileSave_Click(object sender, EventArgs e)
        {
            AppContext.Current.OnSaveFileRequest(new AppCommandEventArgs(AppCommandType.SaveFile));
        }

        /// <summary>
        /// Raises the corresponding AppContext event.
        /// </summary>
        private void mniFileSaveAs_Click(object sender, EventArgs e)
        {
            AppContext.Current.OnSaveFileAsRequest(new AppCommandEventArgs(AppCommandType.SaveFileAs));
        }

        /// <summary>
        /// Raises the corresponding AppContext event.
        /// </summary>
        private void mniFileExit_Click(object sender, EventArgs e)
        {
            AppContext.Current.OnExitApplicationRequest(new AppCommandEventArgs(AppCommandType.ExitApplication));
        }

        /// <summary>
        /// Raises the corresponding AppContext event.
        /// </summary>
        private void mniCommandExecute_Click(object sender, EventArgs e)
        {
            AppContext.Current.OnExecuteRequest(new AppCommandEventArgs(AppCommandType.Execute));
        }

        /// <summary>
        /// Raises the corresponding AppContext event.
        /// </summary>
        private void mniToolsOptions_Click(object sender, EventArgs e)
        {
            AppContext.Current.OnShowOptionsRequest(new AppCommandEventArgs(AppCommandType.ShowOptions));
        }

        /// <summary>
        /// Raises the corresponding AppContext event.
        /// </summary>
        private void mniHelpAbout_Click(object sender, EventArgs e)
        {
            AppContext.Current.OnShowAboutRequest(new AppCommandEventArgs(AppCommandType.ShowAbout));
        }

        /// <summary>
        /// Raises the corresponding AppContext event.
        /// </summary>
        private void tsbNew_Click(object sender, EventArgs e)
        {
            AppContext.Current.OnNewEditorPageRequest(new AppCommandEventArgs(AppCommandType.NewEditorPage));
        }

        /// <summary>
        /// Raises the corresponding AppContext event.
        /// </summary>
        private void tsbExecute_Click(object sender, EventArgs e)
        {
            AppContext.Current.OnExecuteRequest(new AppCommandEventArgs(AppCommandType.Execute));
        }

        /// <summary>
        /// Raises the corresponding AppContext event.
        /// </summary>
        private void tsbOpen_Click(object sender, EventArgs e)
        {
            AppContext.Current.OnOpenFileRequest(new AppCommandEventArgs(AppCommandType.OpenFile));
        }

        /// <summary>
        /// Raises the corresponding AppContext event.
        /// </summary>
        private void tsbSave_Click(object sender, EventArgs e)
        {
            AppContext.Current.OnSaveFileRequest(new AppCommandEventArgs(AppCommandType.SaveFile));
        }

        /// <summary>
        /// Raise the ExecuteRequest event, if the CTRL+E was pressed and the Execute command is available.
        /// </summary>
        private void AppWindow_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Control && e.KeyCode == Keys.E && Availabilities.IsAvailable(AppCommandType.Execute))
            {
                AppContext.Current.OnExecuteRequest(new AppCommandEventArgs(AppCommandType.Execute));
                e.Handled = true;
            }
        }

        #endregion

        #region Handle Active WorksheetTypes
        /// <summary>
        /// Gets the active worksheet type.
        /// </summary>
        private WorksheetType ActiveWorksheetType
        {
            get
            {
                return CurrentWorksheet != null ? CurrentWorksheet.Type : WorksheetManager.DefaultWorksheetType;
            }
        }

        private void mniProgrammingLanguageCSharp_Click(object sender, EventArgs e)
        {
            if (CurrentWorksheet != null)
            {
                CurrentWorksheet.Type = WorksheetType.CSharpScript;

                // Send worksheet type changed notification.
                AppContext.Current.OnAppNotificationReceived(new AppNotificationEventArgs { Type = AppNotificationType.WorksheetTypeChanged });
            }
        }

        /// <summary>
        /// Change Visual Basic as active programming language.
        /// </summary>
        private void mniProgrammingLanguageVb_Click(object sender, EventArgs e)
        {
            if (CurrentWorksheet != null)
            {
                CurrentWorksheet.Type = WorksheetType.VisualBasicScript;

                // Send worksheet type changed notification.
                AppContext.Current.OnAppNotificationReceived(new AppNotificationEventArgs { Type = AppNotificationType.WorksheetTypeChanged });
            }
        }

        private void mniCommandProgrammingLanguage_DropDownOpening(object sender, EventArgs e)
        {
            // C#
            if (ActiveWorksheetType == WorksheetType.CSharpScript)
            {
                mniProgrammingLanguageCSharp.CheckState = CheckState.Checked;
            }
            else
            {
                mniProgrammingLanguageCSharp.CheckState = CheckState.Unchecked;
            }

            // VB
            if (ActiveWorksheetType == WorksheetType.VisualBasicScript)
            {
                mniProgrammingLanguageVb.CheckState = CheckState.Checked;
            }
            else
            {
                mniProgrammingLanguageVb.CheckState = CheckState.Unchecked;
            }
        }
        #endregion

    }
}
